package httpRequestUtils

import (
	"bytes"
	"encoding/json"
	"fmt"
	"io"
	"mime/multipart"
	"net/http"
	"net/url"
	"os"
	"path/filepath"
	"time"
)

// HTTPClient 封装 HTTP 请求工具
type HTTPClient struct {
	BaseURL    string            // 基础 URL
	Headers    map[string]string // 默认请求头
	Timeout    time.Duration     // 请求超时时间
	httpClient *http.Client      // 内部使用的 HTTP 客户端
}

// NewHTTPClient 创建新的 HTTPClient 实例
func NewHTTPClient(baseURL string, headers map[string]string, timeout time.Duration) *HTTPClient {
	if timeout == 0 {
		timeout = 30 * time.Second // 默认超时 30 秒
	}
	return &HTTPClient{
		BaseURL: baseURL,
		Headers: headers,
		Timeout: timeout,
		httpClient: &http.Client{
			Timeout: timeout,
		},
	}
}

// Get 发送 GET 请求
// path: 相对路径
// params: 查询参数
func (c *HTTPClient) Get(path string, params map[string]string) ([]byte, error) {
	// 构建完整 URL
	u, err := url.Parse(c.BaseURL + path)
	if err != nil {
		return nil, fmt.Errorf("URL 解析失败: %v", err)
	}

	// 添加查询参数
	if len(params) > 0 {
		query := u.Query()
		for k, v := range params {
			query.Set(k, v)
		}
		u.RawQuery = query.Encode()
	}

	// 创建请求
	req, err := http.NewRequest("GET", u.String(), nil)
	if err != nil {
		return nil, fmt.Errorf("创建 GET 请求失败: %v", err)
	}

	// 设置请求头
	c.setHeaders(req)

	// 发送请求
	resp, err := c.httpClient.Do(req)
	if err != nil {
		return nil, fmt.Errorf("GET 请求失败: %v", err)
	}
	defer resp.Body.Close()

	// 检查状态码
	if resp.StatusCode != http.StatusOK {
		return nil, fmt.Errorf("GET 请求返回非 200 状态码: %d", resp.StatusCode)
	}

	// 读取响应
	body, err := io.ReadAll(resp.Body)
	if err != nil {
		return nil, fmt.Errorf("读取响应失败: %v", err)
	}

	return body, nil
}

// Post 发送 POST 请求
// path: 相对路径
// data: 请求体数据
// isJSON: true 表示 JSON 格式，false 表示表单格式
func (c *HTTPClient) Post(path string, data interface{}, isJSON bool) ([]byte, error) {
	// 构建完整 URL
	fullURL := c.BaseURL + path

	var body io.Reader
	var contentType string

	if isJSON {
		// JSON 格式
		jsonData, err := json.Marshal(data)
		if err != nil {
			return nil, fmt.Errorf("JSON 编码失败: %v", err)
		}
		body = bytes.NewBuffer(jsonData)
		contentType = "application/json"
	} else {
		// 表单格式
		values, ok := data.(map[string]string)
		if !ok {
			return nil, fmt.Errorf("表单数据必须是 map[string]string 类型")
		}
		formData := url.Values{}
		for k, v := range values {
			formData.Set(k, v)
		}
		body = bytes.NewBufferString(formData.Encode())
		contentType = "application/x-www-form-urlencoded"
	}

	// 创建请求
	req, err := http.NewRequest("POST", fullURL, body)
	if err != nil {
		return nil, fmt.Errorf("创建 POST 请求失败: %v", err)
	}

	// 设置请求头
	c.setHeaders(req)
	req.Header.Set("Content-Type", contentType)

	// 发送请求
	resp, err := c.httpClient.Do(req)
	if err != nil {
		return nil, fmt.Errorf("POST 请求失败: %v", err)
	}
	defer resp.Body.Close()

	// 检查状态码
	if resp.StatusCode != http.StatusOK {
		return nil, fmt.Errorf("POST 请求返回非 200 状态码: %d", resp.StatusCode)
	}

	// 读取响应
	respBody, err := io.ReadAll(resp.Body)
	if err != nil {
		return nil, fmt.Errorf("读取响应失败: %v", err)
	}

	return respBody, nil
}

// UploadFile 发送文件上传请求
// path: 相对路径
// filePath: 本地文件路径
// fieldName: 表单文件字段名称
// params: 额外的表单参数
func (c *HTTPClient) UploadFile(path, filePath, fieldName string, params map[string]string) ([]byte, error) {
	// 打开文件
	file, err := os.Open(filePath)
	if err != nil {
		return nil, fmt.Errorf("打开文件失败: %v", err)
	}
	defer file.Close()

	// 创建multipart表单
	body := &bytes.Buffer{}
	writer := multipart.NewWriter(body)

	// 添加文件
	part, err := writer.CreateFormFile(fieldName, filepath.Base(filePath))
	if err != nil {
		return nil, fmt.Errorf("创建表单文件失败: %v", err)
	}
	_, err = io.Copy(part, file)
	if err != nil {
		return nil, fmt.Errorf("复制文件内容失败: %v", err)
	}

	// 添加额外参数
	for key, value := range params {
		_ = writer.WriteField(key, value)
	}

	// 关闭writer以完成multipart消息
	err = writer.Close()
	if err != nil {
		return nil, fmt.Errorf("关闭multipart writer失败: %v", err)
	}

	// 构建完整URL
	fullURL := c.BaseURL + path

	// 创建请求
	req, err := http.NewRequest("POST", fullURL, body)
	if err != nil {
		return nil, fmt.Errorf("创建文件上传请求失败: %v", err)
	}

	// 设置请求头
	c.setHeaders(req)
	req.Header.Set("Content-Type", writer.FormDataContentType())

	// 发送请求
	resp, err := c.httpClient.Do(req)
	if err != nil {
		return nil, fmt.Errorf("文件上传请求失败: %v", err)
	}
	defer resp.Body.Close()

	// 检查状态码
	if resp.StatusCode != http.StatusOK {
		return nil, fmt.Errorf("文件上传请求返回非200状态码: %d", resp.StatusCode)
	}

	// 读取响应
	respBody, err := io.ReadAll(resp.Body)
	if err != nil {
		return nil, fmt.Errorf("读取响应失败: %v", err)
	}

	return respBody, nil
}

// setHeaders 设置请求的默认 headers
func (c *HTTPClient) setHeaders(req *http.Request) {
	if c.Headers != nil {
		for key, value := range c.Headers {
			req.Header.Set(key, value)
		}
	}
}
